
/*!
\copyright  Copyright (c) 2023 Qualcomm Technologies International, Ltd.
            All Rights Reserved.
            Qualcomm Technologies International, Ltd. Confidential and Proprietary.
\file
\defgroup   list list
\ingroup vm_libs
\brief      List API
*/

#ifndef LIST_H_
#define LIST_H_

#include <stdint.h>
#include <stdbool.h>

/*\{*/

typedef void* list_node_t;
typedef struct _list_t* list_t;

typedef enum list_type_t
{
    list_type_linked_single = 0,
} list_type_t;

typedef enum list_store_t
{
    list_store_variable_size_element = -1,
    list_store_reference = 0,
} list_store_t;

typedef struct list_config_t
{
    /** Select List implementation
     * \see list_type_t
     * 
     * Default: list_type_linked_single
     */
    list_type_t type;

    /** Element store
     * list_store_reference: Store a reference to the element
     * list_store_variable_size_element: Store a copy of the element. Variable element size
     * value > 0: Store a copy of the element. All elements have the size specified by "value"
     *
     * Default: list_store_reference
     */
    union {
        list_store_t type;
        size_t size;
    } element_store;

} list_config_t;


/**
 * \brief Gets the default configuration for the library
 *
 * To know default values for each config option:
 * \see list_config_t
 *
 * Default Config is const, to use it as a base for a custom config it must be copied first
 * \returns A pointer to the Default Configuration
 */
const list_config_t* ListGetDefaultConfig(void);

/**
 * \brief Creates a List
 *
 * \param [in] list_config: Specify the List configuration
 */
list_t ListCreate(const list_config_t* config);

/**
 * \brief Destroys a List
 *
 * \param [in/out] list: List to destroy
 */
void ListDestroy(list_t *list);

/**
 * \brief Checks if the list is empty
 *
 * \param [in] list: List to check
 * 
 * \returns TRUE, if the list is empty
 */
bool ListIsEmpty(list_t list);

/**
 * \brief Returns the head node of the list
 *
 * \param [in] list: A List
 */
list_node_t ListGetHead(const list_t list);

/**
 * \brief Returns the tail node of the list
 *
 * \param [in] list: A List
 */
list_node_t ListGetTail(const list_t list);

/**
 * \brief Returns the next node
 *
 * \param [in] list: List
 * \param [in] node: A node in the list
 */
list_node_t ListGetNext(const list_t list, list_node_t node);

/**
 * \brief Retrieves the Element inside a node
 * 
 * \param [in] list: List
 * \param [in] node: A node in the list
 * 
 * \returns A reference to the element that is stored in the node
 */
void* ListGetElement(const list_t list, list_node_t node);

/**
 * \brief Retrieves the Size of an Element inside a node
 * 
 * \param [in] list: List
 * \param [in] node: A node in the list
 * 
 * \returns A reference to the element that is stored in the node
 */
size_t ListGetElementSize(const list_t list, list_node_t node);

/**
 * \brief Prepend element before the current head of the list
 * 
 * \param [in/out] list: List to prepend to
 * \param [in] element: Element to prepend
 */
void ListPrepend(list_t list, void *element);

/**
 * \brief Append element after the current tail of the list
 * 
 * \param [in/out] list: List to append to
 * \param [in] element: Element to append
 */
void ListAppend(list_t list, void *element);

/**
 * \brief Prepend element before the current head of the list
 * 
 * \param [in/out] list: List to prepend to
 * \param [in] element: Element to prepend
 * \param [in] size: Element size in bytes
 */
void ListPrependWithSize(list_t list, void *element, size_t size);

/**
 * \brief Append element after the current tail of the list
 * 
 * \param [in/out] list: List to append to
 * \param [in] element: Element to append
 * \param [in] size: Element size in bytes
 */
void ListAppendWithSize(list_t list, void *element, size_t size);

/**
 * \brief Delete a node from the List
 * The node and the element within are destroyed
 *
 * \param [in/out] list: List where the node to delete is
 * \param [in] node: node within a List
 */
void ListDeleteNode(list_t list, list_node_t* node);

/**
 * \brief Iterate over a List starting from head
 * This loop supports deleting "iter" while iterating.
 * "iter" cant't be declared before the loop or updated within the loop body
 */
#define LIST_FOREACH(iter, list)   \
    for (list_node_t iter = ListGetHead(list), iter##_next = iter ? ListGetNext(list, iter) : NULL; \
         iter != NULL; \
         iter = iter##_next, iter##_next = iter##_next ? ListGetNext(list, iter##_next) : NULL)

/*\}*/

#endif /* LIST_H_ */
